package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.comment.pojos.*;
import com.heima.comment.service.CommentService;
import com.heima.common.constants.CommentConstants;
import com.heima.common.constants.HotArticleConstants;
import com.heima.feign.article.IArticleClient;
import com.heima.feign.user.IUserClient;
import com.heima.feign.wemedia.IWemediaClient;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.comment.pojos.CommentLikeDto;
import com.heima.model.comment.pojos.CommentLoadDto;
import com.heima.model.comment.pojos.CommentSaveDto;
import com.heima.model.comment.vos.CommentLoadVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.UpdateArticleMess;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.wemedia.dtos.AuthorLikeDto;
import com.heima.model.wemedia.dtos.CommentListDto;
import com.heima.model.wemedia.dtos.WmRepayCommentDto;
import com.heima.utils.common.DateUtils;
import com.heima.utils.thread.CommentThreadLocalUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CommentServiceImpl implements CommentService {
    @Autowired
    private IWemediaClient wemediaClient;
    @Autowired
    private IArticleClient articleClient;//没用
    @Autowired
    private IUserClient userClient;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    /**
     * 保存评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {
        //1、参数校验
        if (dto == null || StringUtils.isEmpty(dto.getContent())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2、登录校验
        Integer userId = CommentThreadLocalUnit.get();
        if (StringUtils.isEmpty(userId.toString())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //3、内容字数不能超过140个
        if (dto.getContent().length() > 140) {
            return ResponseResult.errorResult(AppHttpCodeEnum.COMMENT_NUMBER_TOO_LARGER);
        }
        //4、文章是否可以评论
        ResponseResult articleInfo = articleClient.getArticleInfo(dto);
        //4.1、判断状态码
        if (!articleInfo.getCode().equals(200)) {
            //直接返回
            return articleInfo;
        }
        //4.2、200状态码 解析里面对象
        ApArticleConfig apArticleConfig = JSON.parseObject(JSON.toJSONString(articleInfo.getData()), ApArticleConfig.class);
        //4.3、判断是否可以评论
        if (!apArticleConfig.getIsComment()) {
            //不可以评论 直接返回
            return ResponseResult.errorResult(AppHttpCodeEnum.COMMENT_NOT_ALLOWED);
        }
        //5、审核内容
        ResponseResult responseResult = auditContent(dto);
        if (responseResult != null) return responseResult;
        //6、评论通过审核 保存到mongoDB
        //6.1、远程调用user微服务得到用户信息 用户姓名
        ResponseResult userInfo = userClient.getUseInfo(userId);
        if (!userInfo.getCode().equals(200)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN, "查无此人用户");
        }
        //6.2、获取返回结果里面的信息
        Object data = userInfo.getData();
        ApUser apUser = JSON.parseObject(JSON.toJSONString(data), ApUser.class);
        //6.3、准备保存对象
        if (dto.getCommentId() == null && dto.getArticleId() != null) {
            //这是文章的评论
            ApComment apComment = ApComment.builder()
                    .authorId(apUser.getId())
                    .authorName(apUser.getName())
                    .content(dto.getContent())
                    .entryId(dto.getArticleId())
                    .createdTime(new Date())
                    .flag(0)
                    .likes(0)
                    .reply(0)
                    .type(0)
                    .build();
            //6.4、保存到mongodb
            mongoTemplate.save(apComment);
            log.info("保存到mongodb成功：{}", apComment);

        } else if (dto.getCommentId() != null || dto.getArticleId() == null) {
            //这是评论的回复
            ApCommentRepay apCommentRepay = ApCommentRepay.builder()
                    .commentId(dto.getCommentId())
                    .authorId(userId)
                    .authorName(apUser.getName())
                    .content(dto.getContent())
                    .likes(0)
                    .createdTime(new Date())
                    .updateTime(new Date())
                    .build();
            mongoTemplate.save(apCommentRepay);
            log.info("保存到mongodb成功：{}", apCommentRepay);
        }
        //6.5、往kafka发送消息 评论的回复也算评论
        UpdateArticleMess mess = new UpdateArticleMess();
        mess.setArticleId(dto.getArticleId());
        mess.setType(UpdateArticleMess.UpdateArticleType.COMMENT);
        mess.setAdd(1);
        kafkaTemplate.send(HotArticleConstants.HOT_ARTICLE_SCORE_TOPIC, JSON.toJSONString(mess));
        //7、返回响应结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 审核内容
     *
     * @param dto
     * @return
     */
    public ResponseResult auditContent(CommentSaveDto dto) {
        //5、文本垃圾检测（敏感词 违规词）远程调用为wemedia微服务审核文本方法
        ResponseResult responseResult = wemediaClient.checkComment(dto);
        //5.1、判断
        if (!responseResult.getCode().equals(200)) {
            //不是两百的话，就是其他各种错，直接返回响应（各种错）
            return responseResult;
        }
        return null;
    }

    /**
     * 点赞评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentLikeDto dto) {
        //1、参数判断
        if (dto == null || dto.getOperation() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2、业务处理
        //2.0、取得当前用户id
        Integer userId = CommentThreadLocalUnit.get();
        if (userId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //创建评论喜欢表
        ApCommentLike apCommentLike = new ApCommentLike();
        apCommentLike.setAuthorId(userId);
        ApComment apComment;
        //2.1、根据评论id查到评论 健壮性
        if (dto.getCommentId() != null && dto.getCommentRepayId() == null) {//给文章的评论点赞或取消
            apCommentLike.setCommentId(dto.getCommentId());
            apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
            if (apComment == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "评论不存在");
            }
            //点赞了
            if (dto.getOperation().equals(CommentConstants.LIKE)) {
                //添加到评论喜欢表
                mongoTemplate.save(apCommentLike);
                //修改评论表
                apComment.setLikes(apComment.getLikes() + 1);
                mongoTemplate.findAndReplace(Query.query(Criteria.where("id").is(dto.getCommentId())), apComment);
            }
            //取消点赞
            if (dto.getOperation().equals(CommentConstants.CANCEL_LIKE)) {
                //删除评论喜欢表 根据评论id
                mongoTemplate.remove(Query.query(Criteria.where("commentId").is(dto.getCommentId())), ApCommentLike.class);
                //修改评论表
                apComment.setLikes(apComment.getLikes() - 1);
                mongoTemplate.findAndReplace(Query.query(Criteria.where("id").is(dto.getCommentId())), apComment);

            }
        } else if (dto.getCommentRepayId() != null && dto.getCommentId() == null) {//给评论的回复点赞或取消
            apCommentLike.setCommentId(dto.getCommentRepayId());
            apComment = mongoTemplate.findById(dto.getCommentRepayId(), ApComment.class);
            if (apComment == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "评论不存在");
            }
            //点赞了
            if (dto.getOperation().equals(CommentConstants.LIKE)) {
                //添加到评论喜欢表
                mongoTemplate.save(apCommentLike);
                //修改评论表
                apComment.setLikes(apComment.getLikes() + 1);
                mongoTemplate.findAndReplace(Query.query(Criteria.where("id").is(dto.getCommentRepayId())), apComment);
            }
            //取消点赞
            if (dto.getOperation().equals(CommentConstants.CANCEL_LIKE)) {
                //删除评论喜欢表 根据评论id
                mongoTemplate.remove(Query.query(Criteria.where("commentId").is(dto.getCommentRepayId())), ApCommentLike.class);
                //修改评论表
                apComment.setLikes(apComment.getLikes() - 1);
                mongoTemplate.findAndReplace(Query.query(Criteria.where("id").is(dto.getCommentRepayId())), apComment);

            }
        } else {
            //如果二者都为空或都不为空就有问题了
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //3、返回响应结果
        CommentLoadVo vo = new CommentLoadVo();
        vo.setLikes(apComment.getLikes());
        return ResponseResult.okResult(vo);
    }

    /**
     * 加载评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult loadComment(CommentLoadDto dto) {
        //1、参数校验
        if (dto == null || dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2、业务处理 查询mongodb
        //2.0、创建封装返回对象的集合
        List<CommentLoadVo> list = new ArrayList<>();
        //2.1、得出当前用户id
        Integer userId = CommentThreadLocalUnit.get();
        if (userId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //2.2、先查出该文章下所有的评论
        List<ApComment> apComments = mongoTemplate.find(Query.query(Criteria.where("entryId").is(dto.getArticleId()).and("createdTime").lt(dto.getMinDate())), ApComment.class);
        //2.3、遍历他
        for (ApComment apComment : apComments) {
            //创建返回对象
            CommentLoadVo vo = new CommentLoadVo();
            BeanUtils.copyProperties(apComment, vo);
            //根据评论id 以及用户用户id 查询评论喜欢表
            ApCommentLike like = mongoTemplate.findOne(Query.query(Criteria.where("commentId").is(apComment.getId())
                    .and("authorId").is(userId)).with(Sort.by(Sort.Direction.DESC, "createdTime")), ApCommentLike.class);
            if (like != null) {
                //点赞了 高亮
                vo.setOperation(0);
            }
            //加入返回的集合
            list.add(vo);
        }
        //创建时间倒序  十条
        list = list.stream().sorted(Comparator.comparing(CommentLoadVo::getCreatedTime).reversed()).limit(10).collect(Collectors.toList());
        //返回
        return ResponseResult.okResult(list);
    }

    /**
     * 加载评论回复
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult loadRepay(CommentLoadDto dto) {
        //1、参数校验
        if (dto == null || dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2、业务处理
        //2.1、查询评论回复表
        List<ApCommentRepay> replies = mongoTemplate.find(Query.query(Criteria.where("commentId").is(dto.getCommentId()).and("createdTime").lt(dto.getMinDate())), ApCommentRepay.class);
        //2.2、封装返回对象
        List<CommentLoadVo> list = new ArrayList<>();
        //2.3、当前用户id
        Integer userId = CommentThreadLocalUnit.get();
        if (userId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //2.4、遍历
        for (ApCommentRepay reply : replies) {
            //查询评论点赞表
            ApCommentLike like = mongoTemplate.findOne(Query.query(Criteria.where("commentId").is(reply.getId()).and("authorId").is(userId)), ApCommentLike.class);
            //拷贝属性 集合封装
            CommentLoadVo vo = new CommentLoadVo();
            BeanUtils.copyProperties(reply, vo);
            if (like != null) {
                //高亮
                vo.setOperation(0);
            }
            list.add(vo);
        }
        //2.5、时间倒序 查询十条
        list = list.stream().sorted(Comparator.comparing(CommentLoadVo::getCreatedTime).reversed()).limit(10).collect(Collectors.toList());
        return ResponseResult.okResult(list);
    }

    /**
     * 删除文章对应得评论
     *
     * @param articleId
     */
    @Override
    public void delComment(Long articleId) {
        //1、先得出该文章下所有评论
        List<ApComment> apComments = mongoTemplate.find(Query.query(Criteria.where("entryId").is(articleId)), ApComment.class);
        if (apComments.size() == 0) {
            //没评论直接结束
            return;
        }
        //2、只要其中得评论id
        List<String> commentIds = apComments.stream().map(ApComment::getId).collect(Collectors.toList());
        //3、删除评论表内容
        mongoTemplate.remove(Query.query(Criteria.where("entryId").is(articleId)), ApComment.class);
        //4、批量删除评论点赞表
        mongoTemplate.remove(Query.query(Criteria.where("commentId").in(commentIds)), ApCommentLike.class);
        //5、得出评论回复
        List<ApCommentRepay> apCommentRepays = mongoTemplate.find(Query.query(Criteria.where("commentId").in(commentIds)), ApCommentRepay.class);
        if (apCommentRepays.size() == 0) {
            //评论没回复直接结束方法
            return;
        }
        //5.1、只要其中得回复id
        List<String> commentRepayIds = apCommentRepays.stream().map(ApCommentRepay::getId).collect(Collectors.toList());
        //5.2、删除评论回复点赞
        mongoTemplate.remove(Query.query(Criteria.where("commentId").in(commentRepayIds)), ApCommentRepayLike.class);
        //todo 事务统一，确保删除，可以再查一次，若还有数据，发送消息到kafka，设置一个消费者监听消费
    }

    /**
     * 查看评论详情
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult list(CommentListDto dto) {
        //1、参数校验
        if (dto == null || dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2、业务处理
        //2.0、创建集合封装返回对象
        List<CommentRepayListVo> listVos = new ArrayList<>();
        //2.1、得出当前文章得评论集合
        List<ApComment> apComments = mongoTemplate.find(Query.query(Criteria.where("entryId").is(dto.getArticleId()))
                .skip((long) (dto.getPage() - 1) * dto.getSize()).limit(dto.getSize())
                .with(Sort.by(Sort.Direction.DESC, "CreatedTime")), ApComment.class);
        //2.2、查询每条评论的回复
        for (ApComment apComment : apComments) {
            //创建返回对象 并拷贝属性
            CommentRepayListVo vo = new CommentRepayListVo();
            vo.setApComments(apComment);
            //查询评论回复表
            vo.setApCommentRepays(mongoTemplate.find(Query.query(Criteria.where("commentId")
                                    .is(apComment.getId()))
                            .with(Sort.by(Sort.Direction.DESC, "createdTime")),
                    ApCommentRepay.class));
            //添加到返回集合
            listVos.add(vo);
        }
        return ResponseResult.okResult(listVos);
    }

    /**
     * 作者点赞或取消评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult authorLike(AuthorLikeDto dto) {
        //1、参数校验
        if (dto == null || dto.getOperation() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 得出当前评论点赞数
        ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
        //2、业务处理
        if (apComment != null && dto.getOperation() == 0) {
            //点赞 评论表点赞数加1
            apComment.setLikes(apComment.getLikes() + 1);
            //修改数据
            mongoTemplate.findAndReplace(Query.query(Criteria.where("id").is(dto.getCommentId())), apComment);
            //创建评论点赞对象 并保存
            ApCommentLike like = new ApCommentLike();
            like.setCommentId(dto.getCommentId());
            like.setAuthorId(dto.getUserId());
            mongoTemplate.save(like);
        }
        if (apComment != null && dto.getOperation() == 1) {
            //取消点赞
            apComment.setLikes(apComment.getLikes() - 1 < 1 ? 0 : apComment.getLikes() - 1);//确保非负
            mongoTemplate.findAndReplace(Query.query(Criteria.where("id").is(dto.getCommentId())), apComment);
            //删除评论点赞对象
            mongoTemplate.remove(Query.query(Criteria.where("commentId").is(dto.getCommentId())), ApCommentLike.class);
        }
        //返回对象
        Map<String, Object> map = new HashMap<>();
        map.put("likes", apComment.getLikes());
        return ResponseResult.okResult(map);
    }

    /**
     * 作者回复评论
     * @param dto
     */
    @Override
    public ResponseResult repay(WmRepayCommentDto dto) {
        //1、参数校验
        if (dto == null || dto.getCommentId() == null || StringUtils.isEmpty(dto.getContent())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2、创建评论回复对象
        ApCommentRepay apCommentRepay = ApCommentRepay.builder().commentId(dto.getCommentId())
                .updateTime(new Date())
                .createdTime(new Date())
                .likes(0)
                .authorId(dto.getUserId())
                .content(dto.getContent())
                .authorName(dto.getAuthorName()).build();
        //保存评论回复
        mongoTemplate.save(apCommentRepay);
        //评论表回复数加1
        ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
        if (apComment != null) {
            apComment.setReply(apComment.getReply() + 1);
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}
